﻿using SD.Common;
using SD.Infrastructure.DTOBase;
using SD.OpcProxy.AppService.Maps;
using SD.OpcProxy.Domain.Entities;
using SD.OpcProxy.Domain.IRepositories;
using SD.OpcProxy.Domain.Mediators;
using SD.OpcProxy.IAppService.DTOs.Outputs;
using SD.OpcProxy.IAppService.Interfaces;
using SD.OpcProxy.ValueObjects.Enums;
using System;
using System.Collections.Generic;
using System.Linq;

#if NET461_OR_GREATER
using System.ServiceModel;
#endif
#if NETSTANDARD2_0_OR_GREATER
using CoreWCF;
#endif

namespace SD.OpcProxy.AppService.Implements
{
    /// <summary>
    /// OPC代理服务契约实现
    /// </summary>
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class OpcProxyContract : IOpcProxyContract
    {
        #region # 字段及依赖注入构造器

        /// <summary>
        /// 仓储中介者
        /// </summary>
        private readonly RepositoryMediator _repMediator;

        /// <summary>
        /// 单元事务
        /// </summary>
        private readonly IUnitOfWorkOpcProxy _unitOfWork;

        /// <summary>
        /// 依赖注入构造器
        /// </summary>
        /// <param name="repMediator">仓储中介者</param>
        /// <param name="unitOfWork">单元事务</param>
        public OpcProxyContract(RepositoryMediator repMediator, IUnitOfWorkOpcProxy unitOfWork)
        {
            this._repMediator = repMediator;
            this._unitOfWork = unitOfWork;
        }

        #endregion


        //命令部分

        #region # 创建OPC服务器 —— void CreateOpcServer(string opcServerName, OpcMode opcMode...
        /// <summary>
        /// 创建OPC服务器
        /// </summary>
        /// <param name="opcServerName">OPC服务器名称</param>
        /// <param name="opcMode">OPC模式</param>
        /// <param name="url">服务器地址</param>
        /// <param name="pingInterval">Ping间隔（单位：秒）</param>
        /// <param name="monitorInterval">监听间隔（单位：毫秒）</param>
        /// <param name="timeout">超时时间（单位：秒）</param>
        public void CreateOpcServer(string opcServerName, OpcMode opcMode, string url, int pingInterval, int monitorInterval, int timeout)
        {
            //验证
            Assert.IsFalse(this._repMediator.OpcServerRep.ExistsNo(null, url), "OPC服务器URL已存在！");

            OpcServer server = new OpcServer(opcServerName, opcMode, url, pingInterval, monitorInterval, timeout);

            this._unitOfWork.RegisterAdd(server);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 修改OPC服务器 —— void UpdateOpcServer(Guid opcServerId, string opcServerName...
        /// <summary>
        /// 修改OPC服务器
        /// </summary>
        /// <param name="opcServerId">OPC服务器Id</param>
        /// <param name="opcServerName">OPC服务器名称</param>
        /// <param name="url">服务器地址</param>
        /// <param name="pingInterval">Ping间隔（单位：秒）</param>
        /// <param name="monitorInterval">监听间隔（单位：毫秒）</param>
        /// <param name="timeout">超时时间（单位：秒）</param>
        public void UpdateOpcServer(Guid opcServerId, string opcServerName, string url, int pingInterval, int monitorInterval, int timeout)
        {
            //验证
            Assert.IsFalse(this._repMediator.OpcServerRep.ExistsNo(opcServerId, url));

            OpcServer server = this._unitOfWork.Resolve<OpcServer>(opcServerId);
            server.UpdateInfo(opcServerName, url, pingInterval, monitorInterval, timeout);

            this._unitOfWork.RegisterSave(server);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 删除OPC服务器 —— void RemoveOpcServer(Guid opcServerId)
        /// <summary>
        /// 删除OPC服务器
        /// </summary>
        /// <param name="opcServerId">OPC服务器Id</param>
        public void RemoveOpcServer(Guid opcServerId)
        {
            this._unitOfWork.RegisterRemove<OpcServer>(opcServerId);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 创建变量 —— void CreateVariable(string variableNo, string variableName...
        /// <summary>
        /// 创建变量
        /// </summary>
        /// <param name="variableNo">变量编号</param>
        /// <param name="variableName">变量名称</param>
        /// <param name="variableType">变量类型</param>
        /// <param name="isReadonly">是否只读</param>
        /// <param name="dataType">数据类型</param>
        /// <param name="opcServerId">OPC服务器Id</param>
        /// <param name="unit">单位</param>
        /// <param name="keepRecord">是否记录历史</param>
        /// <param name="description">描述</param>
        /// <param name="valueDescriptions">值描述字典</param>
        public void CreateVariable(string variableNo, string variableName, VariableType variableType, bool isReadonly, string dataType, Guid opcServerId, string unit, bool keepRecord, string description, IDictionary<string, string> valueDescriptions)
        {
            //验证
            Assert.IsFalse(this._repMediator.VariableRep.ExistsNo(variableNo), "变量编号已存在！");

            Variable variable = new Variable(variableNo, variableName, variableType, isReadonly, dataType, opcServerId, unit, keepRecord, description, valueDescriptions);

            this._unitOfWork.RegisterAdd(variable);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 修改变量 —— void UpdateVariable(Guid variableId, string variableName...
        /// <summary>
        /// 修改变量
        /// </summary>
        /// <param name="variableId">变量Id</param>
        /// <param name="variableName">变量名称</param>
        /// <param name="opcServerId">OPC服务器Id</param>
        /// <param name="unit">单位</param>
        /// <param name="keepRecord">是否记录历史</param>
        /// <param name="description">描述</param>
        /// <param name="valueDescriptions">值描述字典</param>
        public void UpdateVariable(Guid variableId, string variableName, Guid opcServerId, string unit, bool keepRecord, string description, IDictionary<string, string> valueDescriptions)
        {
            Variable currentVariable = this._unitOfWork.Resolve<Variable>(variableId);
            currentVariable.UpdateInfo(variableName, opcServerId, unit, keepRecord, description, valueDescriptions);

            this._unitOfWork.RegisterSave(currentVariable);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 删除变量 —— void RemoveVariable(Guid variableId)
        /// <summary>
        /// 删除变量
        /// </summary>
        /// <param name="variableId">变量Id</param>
        public void RemoveVariable(Guid variableId)
        {
            this._unitOfWork.RegisterRemove<Variable>(variableId);
            this._unitOfWork.Commit();
        }
        #endregion


        //查询部分

        #region # 分页获取OPC服务器列表 —— PageModel<OpcServerInfo> GetOpcServersByPage(string keywords...
        /// <summary>
        /// 分页获取OPC服务器列表
        /// </summary>
        /// <param name="keywords">关键字</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页容量</param>
        /// <returns>OPC服务器列表</returns>
        public PageModel<OpcServerInfo> GetOpcServersByPage(string keywords, int pageIndex, int pageSize)
        {
            IEnumerable<OpcServer> opcServers = this._repMediator.OpcServerRep.FindByPage(keywords, pageIndex, pageSize, out int rowCount, out int pageCount);
            IEnumerable<OpcServerInfo> opcServerInfos = opcServers.Select(x => x.ToDTO());

            return new PageModel<OpcServerInfo>(opcServerInfos, pageIndex, pageSize, pageCount, rowCount);
        }
        #endregion

        #region # 分页获取变量列表 —— PageModel<VariableInfo> GetVariablesByPage(string keywords...
        /// <summary>
        /// 分页获取变量列表
        /// </summary>
        /// <param name="keywords">关键字</param>
        /// <param name="variableType">变量类型</param>
        /// <param name="isReadonly">是否只读</param>
        /// <param name="dataTypes">数据类型集</param>
        /// <param name="opcServerId">OPC服务器Id</param>
        /// <param name="keepRecord">是否记录历史</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页容量</param>
        /// <returns>变量列表</returns>
        public PageModel<VariableInfo> GetVariablesByPage(string keywords, VariableType? variableType, bool? isReadonly, IList<string> dataTypes, Guid? opcServerId, bool? keepRecord, int pageIndex, int pageSize)
        {
            ICollection<Variable> variables = this._repMediator.VariableRep.FindByPage(keywords, variableType, isReadonly, dataTypes, opcServerId, keepRecord, pageIndex, pageSize, out int rowCount, out int pageCount);

            IEnumerable<Guid> opcServerIds = variables.Select(x => x.OpcServerId);
            IDictionary<Guid, OpcServerInfo> opcServerInfos = this._repMediator.OpcServerRep.Find(opcServerIds).ToDictionary(x => x.Key, x => x.Value.ToDTO());

            IEnumerable<VariableInfo> variableInfos = variables.Select(x => x.ToDTO(opcServerInfos));

            return new PageModel<VariableInfo>(variableInfos, pageIndex, pageSize, pageCount, rowCount);
        }
        #endregion

        #region # 是否存在OPC服务器地址 —— bool ExistsOpcServer(Guid? opcServerId, string url)
        /// <summary>
        /// 是否存在OPC服务器地址
        /// </summary>
        /// <param name="opcServerId">OPC服务器Id</param>
        /// <param name="url">服务器地址</param>
        /// <returns>是否存在</returns>
        public bool ExistsOpcServer(Guid? opcServerId, string url)
        {
            return this._repMediator.OpcServerRep.ExistsNo(opcServerId, url);
        }
        #endregion

        #region # 是否存在变量编号 —— bool ExistsVariable(string variableNo)
        /// <summary>
        /// 是否存在变量编号
        /// </summary>
        /// <param name="variableNo">变量编号</param>
        /// <returns>是否存在</returns>
        public bool ExistsVariable(string variableNo)
        {
            return this._repMediator.VariableRep.ExistsNo(variableNo);
        }
        #endregion

        #region # 分页获取变量历史列表 —— PageModel<VariableHistoryInfo> GetVariableHistorysByPage(string keywords...
        /// <summary>
        /// 分页获取变量历史列表
        /// </summary>
        /// <param name="keywords">关键字</param>
        /// <param name="variableNo">变量编号</param>
        /// <param name="startTime">开始时间</param>
        /// <param name="endTime">结束时间</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页容量</param>
        /// <returns>变量历史列表</returns>
        public PageModel<VariableHistoryInfo> GetVariableHistorysByPage(string keywords, string variableNo, DateTime? startTime, DateTime? endTime, int pageIndex, int pageSize)
        {
            ICollection<VariableHistory> variableHistories = this._repMediator.VariableHistoryRep.FindByPage(keywords, variableNo, startTime, endTime, pageIndex, pageSize, out int rowCount, out int pageCount);
            IEnumerable<VariableHistoryInfo> variableHistoryInfos = variableHistories.Select(x => x.ToDTO());

            return new PageModel<VariableHistoryInfo>(variableHistoryInfos, pageIndex, pageSize, pageCount, rowCount);
        }
        #endregion
    }
}
